﻿using DevExpress.Xpf.Charts;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Threading;

namespace TeBigCommonUI.Items
{
    public class BaseItemControl : UserControl
    {
        static BaseItemControl()
        {
            EnsureApplicationResources();
        }

        public static void EnsureApplicationResources()
        {
            if (Application.Current != null)
            {
                // merge in your application resources
                Application.Current.Resources.MergedDictionaries.Add(
                    Application.LoadComponent(
                        new Uri("Te.Bigscreen.Common;component/Assets/Xaml/Items.xaml",
                        UriKind.Relative)) as ResourceDictionary);
            }
        }


        private bool AlreadyLoaded = false;

        public BaseItemControl()
        {
            this.Loaded += BaseItemControl_Loaded;
        }

        private void BaseItemControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (AlreadyLoaded)
                return;

            OnInitControl();

            AlreadyLoaded = true;
        }

        protected virtual void OnInitControl()
        {
        }
    }

    public class SeriesDataSource : DependencyObject
    {
        public string DisplayName
        {
            get { return (string)GetValue(DisplayNameProperty); }
            set { SetValue(DisplayNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisplayNameProperty =
            DependencyProperty.Register("DisplayName", typeof(string), typeof(SeriesDataSource), new PropertyMetadata(""));

        public object DataSource
        {
            get { return (object)GetValue(DataSourceProperty); }
            set { SetValue(DataSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DataSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataSourceProperty =
            DependencyProperty.Register("DataSource", typeof(object), typeof(SeriesDataSource), new PropertyMetadata(new object()));

        public string ArgumentDataMember
        {
            get { return (string)GetValue(ArgumentDataMemberProperty); }
            set { SetValue(ArgumentDataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ArgumentDataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ArgumentDataMemberProperty =
            DependencyProperty.Register("ArgumentDataMember", typeof(string), typeof(SeriesDataSource), new PropertyMetadata(""));

        public string ValueDataMember
        {
            get { return (string)GetValue(ValueDataMemberProperty); }
            set { SetValue(ValueDataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ValueDataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueDataMemberProperty =
            DependencyProperty.Register("ValueDataMember", typeof(string), typeof(SeriesDataSource), new PropertyMetadata(""));

        public string Value2DataMember
        {
            get { return (string)GetValue(Value2DataMemberProperty); }
            set { SetValue(Value2DataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Value2DataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Value2DataMemberProperty =
            DependencyProperty.Register("Value2DataMember", typeof(string), typeof(SeriesDataSource), new PropertyMetadata(""));

        public string WeightDataMember
        {
            get { return (string)GetValue(WeightDataMemberProperty); }
            set { SetValue(WeightDataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for WeightDataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WeightDataMemberProperty =
            DependencyProperty.Register("WeightDataMember", typeof(string), typeof(SeriesDataSource), new PropertyMetadata(""));

        public bool LabelVisible
        {
            get { return (bool)GetValue(LabelVisibleProperty); }
            set { SetValue(LabelVisibleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelVisible.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelVisibleProperty =
            DependencyProperty.Register("LabelVisible", typeof(bool), typeof(SeriesDataSource), new PropertyMetadata(false));

        public int LineThickness
        {
            get { return (int)GetValue(LineThicknessProperty); }
            set { SetValue(LineThicknessProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LineThickness.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LineThicknessProperty =
            DependencyProperty.Register("LineThickness", typeof(int), typeof(SeriesDataSource), new PropertyMetadata(2));

        public double BarWidth
        {
            get { return (double)GetValue(BarWidthProperty); }
            set { SetValue(BarWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BarWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BarWidthProperty =
            DependencyProperty.Register("BarWidth", typeof(double), typeof(SeriesDataSource), new PropertyMetadata(0.6d));

        public double DepthTransform
        {
            get { return (double)GetValue(DepthTransformProperty); }
            set { SetValue(DepthTransformProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DepthTransform.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DepthTransformProperty =
            DependencyProperty.Register("DepthTransform", typeof(double), typeof(SeriesDataSource), new PropertyMetadata(0.8d));




        public double HoleRadiusPercent
        {
            get { return (double)GetValue(HoleRadiusPercentProperty); }
            set { SetValue(HoleRadiusPercentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HoleRadiusPercent.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HoleRadiusPercentProperty =
            DependencyProperty.Register("HoleRadiusPercent", typeof(double), typeof(SeriesDataSource), new PropertyMetadata(50d));




        public double Transparency
        {
            get { return (double)GetValue(TransparencyProperty); }
            set { SetValue(TransparencyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Transparency.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TransparencyProperty =
            DependencyProperty.Register("Transparency", typeof(double), typeof(SeriesDataSource), new PropertyMetadata(0d));




        public int? CountTopN
        {
            get { return (int?)GetValue(CountTopNProperty); }
            set { SetValue(CountTopNProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CountTopN.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CountTopNProperty =
            DependencyProperty.Register("CountTopN", typeof(int?), typeof(SeriesDataSource), new PropertyMetadata(null));




        public double? ValueTopN
        {
            get { return (double?)GetValue(ValueTopNProperty); }
            set { SetValue(ValueTopNProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ValueTopN.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueTopNProperty =
            DependencyProperty.Register("ValueTopN", typeof(double?), typeof(SeriesDataSource), new PropertyMetadata(null));


    }

    public class ConstantLineSource : DependencyObject
    {
        protected static readonly object EmptyValue = new object();

        public object Value
        {
            get { return (object)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(ConstantLineSource), new PropertyMetadata(EmptyValue));

        public object Title
        {
            get { return (object)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Title.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(object), typeof(ConstantLineSource), new PropertyMetadata(""));

        public bool Behind
        {
            get { return (bool)GetValue(BehindProperty); }
            set { SetValue(BehindProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Behind.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BehindProperty =
            DependencyProperty.Register("Behind", typeof(bool), typeof(ConstantLineSource), new PropertyMetadata(true));



        public Brush Brush
        {
            get { return (Brush)GetValue(BrushProperty); }
            set { SetValue(BrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Brush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BrushProperty =
            DependencyProperty.Register("Brush", typeof(Brush), typeof(ConstantLineSource), 
                new PropertyMetadata(new SolidColorBrush(Color.FromArgb(0xdf, 0x73, 0xc6, 0xe4))));


    }

    public class LegendSource : DependencyObject
    {


        public LegendMarkerMode MarkerMode
        {
            get { return (LegendMarkerMode)GetValue(MarkerModeProperty); }
            set { SetValue(MarkerModeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LegendMarkerMode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MarkerModeProperty =
            DependencyProperty.Register("MarkerMode", typeof(LegendMarkerMode), typeof(LegendSource), 
                new PropertyMetadata(LegendMarkerMode.CheckBox));



        public HorizontalPosition HorizontalPosition
        {
            get { return (HorizontalPosition)GetValue(HorizontalPositionProperty); }
            set { SetValue(HorizontalPositionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HorizontalPosition.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HorizontalPositionProperty =
            DependencyProperty.Register("HorizontalPosition", typeof(HorizontalPosition), typeof(LegendSource), 
                new PropertyMetadata(HorizontalPosition.Center));





        public VerticalPosition VerticalPosition
        {
            get { return (VerticalPosition)GetValue(VerticalPositionProperty); }
            set { SetValue(VerticalPositionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for VerticalPosition.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VerticalPositionProperty =
            DependencyProperty.Register("VerticalPosition", typeof(VerticalPosition), typeof(LegendSource),
                new PropertyMetadata(VerticalPosition.BottomOutside));






        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(LegendSource), 
                new PropertyMetadata(Orientation.Horizontal));





        public Thickness IndentFromDiagram
        {
            get { return (Thickness)GetValue(IndentFromDiagramProperty); }
            set { SetValue(IndentFromDiagramProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IndentFromDiagramProperty =
            DependencyProperty.Register("IndentFromDiagram", typeof(Thickness), typeof(LegendSource), 
                new PropertyMetadata(new Thickness(0, 16,0,0)));




        public double ScaleX
        {
            get { return (double)GetValue(ScaleXProperty); }
            set { SetValue(ScaleXProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleXProperty =
            DependencyProperty.Register("ScaleX", typeof(double), typeof(LegendSource), new PropertyMetadata(1d));



        public double ScaleY
        {
            get { return (double)GetValue(ScaleYProperty); }
            set { SetValue(ScaleYProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleYProperty =
            DependencyProperty.Register("ScaleY", typeof(double), typeof(LegendSource), new PropertyMetadata(1d));



    }

    public abstract class BaseChartControl : BaseItemControl
    {
        #region propdp

        public bool LabelVisible
        {
            get { return (bool)GetValue(LabelVisibleProperty); }
            set { SetValue(LabelVisibleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelVisible.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelVisibleProperty =
            DependencyProperty.Register("LabelVisible", typeof(bool), typeof(BaseChartControl), new PropertyMetadata(false));

        public int MirrorHeight
        {
            get { return (int)GetValue(MirrorHeightProperty); }
            set { SetValue(MirrorHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MirrorHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MirrorHeightProperty =
            DependencyProperty.Register("MirrorHeight", typeof(int), typeof(BaseChartControl), new PropertyMetadata(30));


        public CustomPalette Palette
        {
            get { return (CustomPalette)GetValue(PaletteProperty); }
            set { SetValue(PaletteProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Palette.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PaletteProperty =
            DependencyProperty.Register("Palette", typeof(CustomPalette), typeof(XYDiagramChartControl),
                new PropertyMetadata(new CustomPalette()));



        public ChartAnimationMode AnimationMode
        {
            get { return (ChartAnimationMode)GetValue(AnimationModeProperty); }
            set { SetValue(AnimationModeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AnimationMode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AnimationModeProperty =
            DependencyProperty.Register("AnimationMode", typeof(ChartAnimationMode), typeof(BaseChartControl),
                new PropertyMetadata(ChartAnimationMode.Disabled));



        public ObservableCollection<SeriesDataSource> SeriesDataSources
        {
            get { return (ObservableCollection<SeriesDataSource>)GetValue(SeriesDataSourcesProperty); }
        }

        // Using a DependencyProperty as the backing store for SeriesDataSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SeriesDataSourcesProperty =
            DependencyProperty.Register("SeriesDataSources", typeof(ObservableCollection<SeriesDataSource>), typeof(BaseChartControl),
                new PropertyMetadata(new ObservableCollection<SeriesDataSource>()));




        public ObservableCollection<LegendSource> LegendSources
        {
            get { return (ObservableCollection<LegendSource>)GetValue(LegendSourcesProperty); }
        }

        // Using a DependencyProperty as the backing store for LegendSources.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LegendSourcesProperty =
            DependencyProperty.Register("LegendSources", typeof(ObservableCollection<LegendSource>), typeof(BaseChartControl),
                new PropertyMetadata(new ObservableCollection<LegendSource>()));

        #endregion

        private ChartControl chart_ = null;
        private Diagram chart_diagram_ = null;


        public BaseChartControl()
        {
            SetValue(SeriesDataSourcesProperty, new ObservableCollection<SeriesDataSource>());
            SetValue(LegendSourcesProperty, new ObservableCollection<LegendSource>());
            SetValue(PaletteProperty, new CustomPalette());
        }

        protected virtual Legend CreateLegend(IList<LegendSource> source, int index)
        {
            var item = source[index];

            return new Legend
            {
                MarkerMode = item.MarkerMode,
                HorizontalPosition = item.HorizontalPosition,
                VerticalPosition = item.VerticalPosition,
                Orientation = item.Orientation,
                IndentFromDiagram = item.IndentFromDiagram,
                LayoutTransform = new ScaleTransform
                {
                    CenterX = 0.5,
                    CenterY = 0.5,
                    ScaleX = item.ScaleX,
                    ScaleY = item.ScaleY,
                }
            };
        }

        protected virtual Series CreateSeries(IList<SeriesDataSource> source, int index)
        {
            var item = source[index];

            var series = CreateSeriesFromDataSource(source, index);

            SetSeriesProperty(series, item);

            return series;
        }

        protected abstract Series CreateSeriesFromDataSource(IList<SeriesDataSource> source, int index);

        protected void SetSeriesProperty(Series series, SeriesDataSource item)
        {
            series.DisplayName = item.DisplayName;
            series.ArgumentDataMember = item.ArgumentDataMember;
            series.ValueDataMember = item.ValueDataMember;
            series.LabelsVisibility = item.LabelVisible;

            //switch (series)
            //{
            //    case PointSeries2D a:
            //    case LineSeries2D b:
            //    case AreaSeries2D c:
            //    case BubbleSeries2D d:
            //        series.SetPointAnimation(new Marker2DSlideFromLeftCenterAnimation());
            //        break;

            //    case BarSeries2D x:
            //        series.SetPointAnimation(new Bar2DGrowUpAnimation());
            //        break;

            //    case PieSeries2D y:
            //        series.SetPointAnimation(new Pie2DGrowUpAnimation());
            //        break;
            //    default:
            //        break;
            //}


            if (series is BarSeries2D bar_series)
            {
                bar_series.BarWidth = item.BarWidth;
            }

            if (item.CountTopN != null)
            {
                series.TopNOptions = new CountTopNOptions
                {
                    Count = item.CountTopN.Value,
                    ShowOthers = false,
                };
            }
            else if (item.ValueTopN != null)
            {
                series.TopNOptions = new ValueTopNOptions
                {
                    Value = item.ValueTopN.Value,
                    ShowOthers = false,
                };
            }

            var binding = BindingOperations.GetBinding(item, SeriesDataSource.DataSourceProperty);

            if (binding != null)
                series.SetBinding(Series.DataSourceProperty, binding);
            else
                series.DataSource = item.DataSource;

            if (series.DataSource is DataTable dt)
                dt.TableCleared += Dt_TableCleared;

            series.Tag = item;
        }

        private void Dt_TableCleared(object sender, DataTableClearEventArgs e)
        {
            UpdateChartInternal();
        }

        private async void UpdateChartInternal()
        {
            await Task.Delay(TimeSpan.FromSeconds(1));

            chart_?.Dispatcher.Invoke(() => chart_?.UpdateData());
        }

        protected void UpdateSeriesInternal(int index, Diagram chart_diagram, SeriesDataSource item)
        {
            if (index < chart_diagram.Series.Count)
            {
                SetSeriesProperty(chart_diagram.Series[index], item);
            }
        }

        protected virtual void InitChartInternal(ChartControl chart, Diagram chart_diagram)
        {
            chart_ = chart;
            chart_diagram_ = chart_diagram;

            if (Palette.Count == 0)
            {
                Palette = ChartPalette.DefaultPalette();
            }

            BindingOperations.SetBinding(chart_, ChartControlBase.PaletteProperty,
                new Binding() { Source = this.Palette });

            for (int i = chart_diagram.Series.Count; i < this.SeriesDataSources.Count; i++)
            {
                chart_diagram.Series.Add(CreateSeries(this.SeriesDataSources, i));
            }

            for (int i = chart.Legends.Count; i < this.LegendSources.Count; i++)
            {
                chart.Legends.Add(CreateLegend(this.LegendSources, i));
            }
        }

        public void UpdateSeries(int index)
        {
            if (chart_diagram_ == null) return;

            if (index < this.SeriesDataSources.Count)
            {
                var item = this.SeriesDataSources[index];
                foreach (var series in chart_diagram_.Series)
                {
                    if (series.Tag == item)
                    {
                        SetSeriesProperty(series, item);
                        break;
                    }
                }
            }

            UpdateChartInternal();
        }

        public void UpdateSeries()
        {
            if (chart_diagram_ == null) return;

            chart_diagram_.Series.Clear();

            OnInitChart();

            foreach (var series in chart_diagram_.Series)
            {
                if (series.Tag is SeriesDataSource item)
                {
                    SetSeriesProperty(series, item);
                }
            }

            UpdateChartInternal();
        }

        public void ReloadSeries()
        {
            OnInitChart();
        }


        protected override void OnInitControl()
        {
            base.OnInitControl();

            OnInitChart();
        }

        protected virtual void OnInitChart()
        {

        }

        protected virtual void OnClearChart()
        {

        }


    }

    public abstract class BaseXYChartControl : BaseChartControl
    {
        public BaseXYChartControl()
        {
            SetValue(ConstantLineSourcesProperty, new ObservableCollection<ConstantLineSource>());
        }

        public ObservableCollection<ConstantLineSource> ConstantLineSources
        {
            get { return (ObservableCollection<ConstantLineSource>)GetValue(ConstantLineSourcesProperty); }
        }

        // Using a DependencyProperty as the backing store for SeriesDataSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ConstantLineSourcesProperty =
            DependencyProperty.Register("ConstantLines", typeof(ObservableCollection<ConstantLineSource>), typeof(BaseXYChartControl),
                new PropertyMetadata(new ObservableCollection<ConstantLineSource>()));

        public bool LabelXRotate
        {
            get { return (bool)GetValue(LabelXRotateProperty); }
            set { SetValue(LabelXRotateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelXRotate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelXRotateProperty =
            DependencyProperty.Register("LabelXRotate", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public bool LabelYRotate
        {
            get { return (bool)GetValue(LabelYRotateProperty); }
            set { SetValue(LabelYRotateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelYRotate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelYRotateProperty =
            DependencyProperty.Register("LabelYRotate", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public AxisAlignment AxisXAlignment => ReverseXAlignment ? AxisAlignment.Far : AxisAlignment.Near;
        public AxisAlignment AxisYAlignment => ReverseYAlignment ? AxisAlignment.Far : AxisAlignment.Near;

        public bool ReverseXAlignment
        {
            get { return (bool)GetValue(ReverseXAlignmentProperty); }
            set { SetValue(ReverseXAlignmentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ReverseXAlignment.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ReverseXAlignmentProperty =
            DependencyProperty.Register("ReverseXAlignment", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public bool ReverseYAlignment
        {
            get { return (bool)GetValue(ReverseYAlignmentProperty); }
            set { SetValue(ReverseYAlignmentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ReverseYAlignment.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ReverseYAlignmentProperty =
            DependencyProperty.Register("ReverseYAlignment", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public bool ReverseX
        {
            get { return (bool)GetValue(ReverseXProperty); }
            set { SetValue(ReverseXProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RerverseX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ReverseXProperty =
            DependencyProperty.Register("ReverseX", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public bool ReverseY
        {
            get { return (bool)GetValue(ReverseYProperty); }
            set { SetValue(ReverseYProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ReverseY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ReverseYProperty =
            DependencyProperty.Register("ReverseY", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public bool LabelXVisible
        {
            get { return (bool)GetValue(LabelXVisibleProperty); }
            set { SetValue(LabelXVisibleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelXVisible.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelXVisibleProperty =
            DependencyProperty.Register("LabelXVisible", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public bool ActualLabelYVisible => LabelVisible || LabelYVisible;
        public bool ActualLabelXVisible => LabelVisible || LabelXVisible;

        public bool LabelYVisible
        {
            get { return (bool)GetValue(LabelYVisibleProperty); }
            set { SetValue(LabelYVisibleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelYVisible.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelYVisibleProperty =
            DependencyProperty.Register("LabelYVisible", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));




        public Brush AxisBrush
        {
            get { return (Brush)GetValue(AxisBrushProperty); }
            set { SetValue(AxisBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AxisBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AxisBrushProperty =
            DependencyProperty.Register("AxisBrush", typeof(Brush), typeof(XYDiagramChartControl), new PropertyMetadata(null));


    }

    public abstract class XYDiagramChartControl : BaseXYChartControl
    {
        protected override void InitChartInternal(ChartControl chart, Diagram chart_diagram)
        {
            base.InitChartInternal(chart, chart_diagram);

            if (chart_diagram is XYDiagram2D xy_chart_diagram)
            {
                xy_chart_diagram.Rotated = this.Rotated;
                xy_chart_diagram.LabelsResolveOverlappingMinIndent = 2;

                foreach (var item in this.ConstantLineSources)
                {
                    var cl = new ConstantLine()
                    {
                        Brush = item.Brush,
                    };

                    BindingOperations.SetBinding(cl, ConstantLine.ValueProperty,
                            BindingOperations.GetBinding(item, ConstantLineSource.ValueProperty));

                    if (item.Behind)
                        xy_chart_diagram.ActualAxisY.ConstantLinesBehind.Add(cl);
                    else
                        xy_chart_diagram.ActualAxisY.ConstantLinesInFront.Add(cl);
                }
            }
        }



        public bool Rotated
        {
            get { return (bool)GetValue(RotatedProperty); }
            set { SetValue(RotatedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Horizontal.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RotatedProperty =
            DependencyProperty.Register("Rotated", typeof(bool), typeof(XYDiagramChartControl), new PropertyMetadata(false));

        public int SeriesCount
        {
            get { return (int)GetValue(SeriesCountProperty); }
            set { SetValue(SeriesCountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SeriesCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SeriesCountProperty =
            DependencyProperty.Register("SeriesCount", typeof(int), typeof(XYDiagramChartControl), new PropertyMetadata(1));


    }

    public abstract class SimpleDiagramChartControl : BaseChartControl
    {


        public PieLabelPosition LabelPosition
        {
            get { return (PieLabelPosition)GetValue(LabelPositionProperty); }
            set { SetValue(LabelPositionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelPosition.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelPositionProperty =
            DependencyProperty.Register("LabelPosition", typeof(PieLabelPosition), typeof(SimpleDiagramChartControl), 
                new PropertyMetadata(PieLabelPosition.TwoColumns));


        public string LabelTextPattern
        {
            get { return (string)GetValue(LabelTextPatternProperty); }
            set { SetValue(LabelTextPatternProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelTextPattern.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelTextPatternProperty =
            DependencyProperty.Register("LabelTextPattern", typeof(string), typeof(SimpleDiagramChartControl), 
                new PropertyMetadata("{A}:{V}"));


    }

    public abstract class X1Y2DiagramChartControl : XYDiagramChartControl
    {
        protected override void InitChartInternal(ChartControl chart, Diagram chart_diagram)
        {
            base.InitChartInternal(chart, chart_diagram);

            for (int i = 0; i < this.SeriesDataSources2.Count; i++)
            {
                var s = CreateSeries(this.SeriesDataSources2, i);

                if (s is XYSeries2D xys && chart_diagram is XYDiagram2D xy_chart_diagram && xy_chart_diagram.SecondaryAxesY.Count > 0)
                {
                    xys.AxisY = xy_chart_diagram.SecondaryAxesY[0];
                }

                chart_diagram.Series.Add(s);
            }
        }

        public ObservableCollection<SeriesDataSource> SeriesDataSources2
        {
            get { return (ObservableCollection<SeriesDataSource>)GetValue(SeriesDataSources2Property); }
        }

        // Using a DependencyProperty as the backing store for SeriesDataSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SeriesDataSources2Property =
            DependencyProperty.Register("SeriesDataSources2", 
                typeof(ObservableCollection<SeriesDataSource>), 
                typeof(X1Y2DiagramChartControl),
                new PropertyMetadata(new ObservableCollection<SeriesDataSource>()));


        public X1Y2DiagramChartControl()
        {
            SetValue(SeriesDataSources2Property, new ObservableCollection<SeriesDataSource>());
        }
    }

    public abstract class CombinedChartControl : BaseXYChartControl
    {
    }

    public class SimpleGaugeControl : BaseItemControl
    {
        public double MaxValue
        {
            get { return (double)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(double), typeof(SimpleGaugeControl), new PropertyMetadata(100d));

        public double MinValue
        {
            get { return (double)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MinValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinValueProperty =
            DependencyProperty.Register("MinValue", typeof(double), typeof(SimpleGaugeControl), new PropertyMetadata(0d));

        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(SimpleGaugeControl), new PropertyMetadata(50d));
    }

    public class GridColumn : DependencyObject
    {
        public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Name", typeof(string), typeof(GridColumn), new PropertyMetadata(""));

        public string ValueDataMember
        {
            get { return (string)GetValue(ValueDataMemberProperty); }
            set { SetValue(ValueDataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ValueDataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueDataMemberProperty =
            DependencyProperty.Register("ValueDataMember", typeof(string), typeof(GridColumn), new PropertyMetadata(""));

        public string FormatString
        {
            get { return (string)GetValue(FormatStringProperty); }
            set { SetValue(FormatStringProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FormatString.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FormatStringProperty =
            DependencyProperty.Register("FormatString", typeof(string), typeof(GridColumn), new PropertyMetadata("{0}"));

        public Brush Foreground
        {
            get { return (Brush)GetValue(ForegroundProperty); }
            set { SetValue(ForegroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Foregroud.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ForegroundProperty =
            DependencyProperty.Register("Foreground", typeof(Brush), typeof(GridColumn), new PropertyMetadata(null));

        public int TopN
        {
            get { return (int)GetValue(TopNProperty); }
            set { SetValue(TopNProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TopN.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TopNProperty =
            DependencyProperty.Register("TopN", typeof(int), typeof(GridColumn), new PropertyMetadata(0));

        public Brush TopNBrush
        {
            get { return (Brush)GetValue(TopNBrushProperty); }
            set { SetValue(TopNBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TopNBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TopNBrushProperty =
            DependencyProperty.Register("TopNBrush", typeof(Brush), typeof(GridColumn),
                new PropertyMetadata(new SolidColorBrush(Colors.Red)));



        public Brush NegativeBrush
        {
            get { return (Brush)GetValue(NegativeBrushProperty); }
            set { SetValue(NegativeBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for NegativeBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NegativeBrushProperty =
            DependencyProperty.Register("NegativeBrush", typeof(Brush), typeof(GridColumn), new PropertyMetadata(null));




        public HorizontalAlignment HorizontalAlignment
        {
            get { return (HorizontalAlignment)GetValue(HorizontalAlignmentProperty); }
            set { SetValue(HorizontalAlignmentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HorizontalAlignment.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HorizontalAlignmentProperty =
            DependencyProperty.Register("HorizontalAlignment", typeof(HorizontalAlignment), typeof(GridColumn), 
                new PropertyMetadata(HorizontalAlignment.Center));





        public VerticalAlignment VerticalAlignment
        {
            get { return (VerticalAlignment)GetValue(VerticalAlignmentProperty); }
            set { SetValue(VerticalAlignmentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for VerticalAlignment.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VerticalAlignmentProperty =
            DependencyProperty.Register("VerticalAlignment", typeof(VerticalAlignment), typeof(GridColumn), 
                new PropertyMetadata(VerticalAlignment.Center));




        public double? WidthPercent
        {
            get { return (double?)GetValue(WidthPercentProperty); }
            set { SetValue(WidthPercentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for WidthPercent.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WidthPercentProperty =
            DependencyProperty.Register("WidthPercent", typeof(double?), typeof(GridColumn), 
                new PropertyMetadata(null));



        public Thickness CellPadding
        {
            get { return (Thickness)GetValue(CellPaddingProperty); }
            set { SetValue(CellPaddingProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CellMargin.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CellPaddingProperty =
            DependencyProperty.Register("CellPadding", typeof(Thickness), typeof(GridColumn), 
                new PropertyMetadata(new Thickness(0)));


    }

    

    public class SimpleNewsControl : BaseItemControl
    {
        protected static readonly object EmptyDataSource = new object();

        public object DataSource
        {
            get { return (object)GetValue(DataSourceProperty); }
            set { SetValue(DataSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DataSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataSourceProperty =
            DependencyProperty.Register("DataSource", typeof(object), typeof(SimpleNewsControl), new PropertyMetadata(EmptyDataSource));

        public string TitleDataMember
        {
            get { return (string)GetValue(TitleDataMemberProperty); }
            set { SetValue(TitleDataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TitleDataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TitleDataMemberProperty =
            DependencyProperty.Register("TitleDataMember", typeof(string), typeof(SimpleNewsControl), new PropertyMetadata(""));

        public string ContentDataMember
        {
            get { return (string)GetValue(ContentDataMemberProperty); }
            set { SetValue(ContentDataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ContentDataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ContentDataMemberProperty =
            DependencyProperty.Register("ContentDataMember", typeof(string), typeof(SimpleNewsControl), new PropertyMetadata(""));

        public string DateTimeDataMember
        {
            get { return (string)GetValue(DateTimeDataMemberProperty); }
            set { SetValue(DateTimeDataMemberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DateTimeDataMember.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DateTimeDataMemberProperty =
            DependencyProperty.Register("DateTimeDataMember", typeof(string), typeof(SimpleNewsControl), new PropertyMetadata(""));
    }
}